﻿using System.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace Z1029.NoteEditor
{
    public class NoteDataEditorCtrl : MonoBehaviour
    {
        public Note selectNote;
        public List<Note> selectNotes;
        public bool multiSelect;
        public Z1029WindowControl window;
        public RectTransform re;
        public Camera cam;
        public bool cloningNote;
        bool dataUpdating;

        //Model

        //@1:Single
        public NoteData noteData;
        public Note.Direction dir;

        //@2:Multi
        [Serializable]
        public class MultiNoteData
        {
            public NoteType? type;
            public string positionX;
            public float? speed;
            public int? beatTime;
            public int? beatHoldTime;
        }
        public MultiNoteData dats;
        public Note.Direction? dirs;


        //View
        public Dropdown noteType;
        public Dropdown direction;
        public InputField speed;
        public InputField holdTime;
        public InputField time;
        public InputField posX;

        public void Init()
        {
            cam = LevelController.instance.viewCam;
            if (!multiSelect)
            {
                noteData.type = selectNote.type;
                dir = selectNote.direction;
                noteData.beatTime = selectNote.noteData.beatTime;
                noteData.beatHoldTime = selectNote.noteData.beatHoldTime;
                noteData.speed = selectNote.noteData.speed;
                noteData.positionX = selectNote.noteData.positionX;
            }
            else
            {
                selectNotes.Sort();
                // type
                if (selectNotes.All(x => (x.type == selectNotes[0].type)))
                {
                    dats.type = selectNotes[0].type;
                }
                else
                {
                    dats.type = null;
                }
                //BeatTime
                if (selectNotes.All(x => (x.noteData.beatTime == selectNotes[0].noteData.beatTime)))
                {
                    dats.beatTime = selectNotes[0].noteData.beatTime;
                }
                else
                {
                    dats.beatTime = null;
                }
                //HoldTime
                if (selectNotes.All(x => (x.noteData.beatHoldTime == selectNotes[0].noteData.beatHoldTime)))
                {
                    dats.beatHoldTime = selectNotes[0].noteData.beatHoldTime;
                }
                else
                {
                    dats.beatHoldTime = null;
                }
                //Speed
                if (selectNotes.All(x => (x.noteData.speed == selectNotes[0].noteData.speed)))
                {
                    dats.speed = selectNotes[0].noteData.speed;
                }
                else
                {
                    dats.speed = null;
                }
                //PosX
                if (selectNotes.All(x => (x.noteData.positionX == selectNotes[0].noteData.positionX)))
                {
                    string str = selectNotes[0].noteData.positionX.ToString();
                    dats.positionX = str;
                }
                else
                {
                    dats.positionX = null;
                }
                //Direction
                if (selectNotes.All(x => (x.direction == selectNotes[0].direction)))
                {
                    dirs = selectNotes[0].direction;
                }
                else
                {
                    dirs = null;
                }
            }
            UpdateData();
        }

        void Update()
        {
            //快捷键
            if (Input.GetKeyDown(KeyCode.Delete))
            {
                Delete();
            }
            if (Input.GetKey(KeyCode.LeftControl) && Input.GetKeyDown(KeyCode.D))
            {
                Clone();
            }
            if (Input.GetKeyDown(KeyCode.Return))
            {
                Submit();
            }
            if (Input.GetKeyDown(KeyCode.Escape))
            {
                Cancel();
            }

            //移动note
            if (CanGenerateNote() && Input.GetMouseButton(0))
            {
            }
            if (CanGenerateNote() && Input.GetMouseButtonDown(0))
            {
                if (multiSelect)
                {
                    float sx = new Vector3(cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x - RectToMouse(re).x, Input.mousePosition.y - RectToMouse(re).y, LevelController.instance.camDistance)).x, cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x - RectToMouse(re).x, Input.mousePosition.y - RectToMouse(re).y, 8)).y, 0).x;
                    posX.text = sx.ToString() + "—0";
                }
            }
            if (multiSelect && Input.GetMouseButtonUp(0) && CanGenerateNote())
            {
                float ex = new Vector3(cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x - RectToMouse(re).x, Input.mousePosition.y - RectToMouse(re).y, LevelController.instance.camDistance)).x, cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x - RectToMouse(re).x, Input.mousePosition.y - RectToMouse(re).y, 8)).y, 0).x;
                posX.text = posX.text.Split('—')[0] + "—" + ex.ToString();
                ChangeData();
                UpdateData();
            }

            if (CanGenerateNote() && Input.GetMouseButton(1))
            {
                /*
                if (!multiSelect)
                {
                    float posY = new Vector3(cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x - RectToMouse(re).x, Input.mousePosition.y - RectToMouse(re).y, LevelController.instance.camDistance)).x, cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x - RectToMouse(re).x, Input.mousePosition.y - RectToMouse(re).y, 8)).y, 0).y;
                    int newT = Utils.GetBeatTimeFromTime(LevelController.instance.judgelines[0].DistanceToTime(posY, dir == Note.Direction.Below), LevelController.instance.judgelines[0].bpm);
                    newT = Mathf.RoundToInt(newT / (LevelController.instance.nowDensity)) * (LevelController.instance.nowDensity);
                    noteData.beatTime = newT;
                    if (ViewCtrl.viewType == ViewCtrl.ViewType.Move) selectNote.noteData.beatTime = newT;
                    UpdateData();
                }*/
            }
            if (CanGenerateNote() && Input.GetMouseButtonDown(1))
            {
                /*if (multiSelect)
                {
                    float sy = new Vector3(cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x - RectToMouse(re).x, Input.mousePosition.y - RectToMouse(re).y, LevelController.instance.camDistance)).x, cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x - RectToMouse(re).x, Input.mousePosition.y - RectToMouse(re).y, 8)).y, 0).y;
                    //posX.text = sy.ToString() +"—" ;
                }*/
                Delete();
            }
            if (multiSelect && Input.GetMouseButtonUp(1))
            {
                //float ey = new Vector3(cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x - RectToMouse(re).x, Input.mousePosition.y - RectToMouse(re).y, LevelController.instance.camDistance)).x, cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x - RectToMouse(re).x, Input.mousePosition.y - RectToMouse(re).y, 8)).y, 0).y;
                //posX.text = posX.text + ex.ToString();
            }
        }

        public void SetPosX()
        {
            if (!multiSelect)
            {
                noteData.positionX = new Vector3(cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x - RectToMouse(re).x, Input.mousePosition.y - RectToMouse(re).y, LevelController.instance.camDistance)).x, cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x - RectToMouse(re).x, Input.mousePosition.y - RectToMouse(re).y, 8)).y, 0).x;
                selectNote.noteData.positionX = new Vector3(cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x - RectToMouse(re).x, Input.mousePosition.y - RectToMouse(re).y, LevelController.instance.camDistance)).x, cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x - RectToMouse(re).x, Input.mousePosition.y - RectToMouse(re).y, 8)).y, 0).x;
                UpdateData();
            }
        }

        public void ChangeData()
        {
            if (!multiSelect)
            {
                noteData.type = (NoteType)noteType.value;
                dir = (Note.Direction)direction.value;
                noteData.beatTime = int.Parse(time.text);
                noteData.beatHoldTime = int.Parse(holdTime.text);
                noteData.speed = float.Parse(speed.text);
                noteData.positionX = float.Parse(posX.text);
            }
            else
            {
                if (noteType.value != 4) dats.type = (NoteType)noteType.value;
                else dats.type = null;
                if (direction.value != 2) dirs = (Note.Direction)direction.value;
                else dirs = null;
                if (time.text != "-") dats.beatTime = int.Parse(time.text);
                else dats.beatTime = null;
                if (holdTime.text != "-") dats.beatHoldTime = int.Parse(holdTime.text);
                else dats.beatHoldTime = null;
                if (speed.text != "-") dats.speed = float.Parse(speed.text);
                else dats.speed = null;
                if (posX.text != "-")
                {
                    if (posX.text.Contains("—"))
                    {
                        string input = posX.text;
                        float start = float.Parse(input.Split('—')[0]);
                        float end = float.Parse(input.Split('—')[1]);
                        if (input.Split('—').Length == 3) dats.positionX = start + "—" + end + "—" + input.Split('—')[2];
                        else dats.positionX = start + "—" + end;
                    }
                    else
                    {
                        dats.positionX = posX.text;
                    }
                }
                else
                {
                    dats.positionX = posX.text;
                }
            }
            UpdateData();
        }

        public void ChangeTypeValue()
        {
            if (!multiSelect)
            {
                noteData.type = (NoteType)noteType.value;
                //dir = (Note.Direction)direction.value;
            }
            else
            {
                if (noteType.value != 4) dats.type = (NoteType)noteType.value;
                else dats.type = null;
                //if (direction.value != 2) dirs = (Note.Direction)direction.value;
                //else dirs = null;
            }
        }

        public void ChangeDirValue()
        {
            if (!multiSelect)
            {
                //noteData.type = (NoteType)noteType.value;
                dir = (Note.Direction)direction.value;
            }
            else
            {
                //if (noteType.value != 4) dats.type = (NoteType)noteType.value;
                //else dats.type = null;
                if (direction.value != 2) dirs = (Note.Direction)direction.value;
                else dirs = null;
            }
        }

        public void AttachToBeatline()
        {
            if (!multiSelect)
            {
                selectNote.noteData.beatTime = Mathf.RoundToInt(noteData.beatTime / LevelController.instance.nowDensity) * LevelController.instance.nowDensity;
            }
            else
            {
                foreach (Note n in selectNotes)
                {
                    n.noteData.beatTime = Mathf.RoundToInt(n.noteData.beatTime / LevelController.instance.nowDensity) * LevelController.instance.nowDensity;
                }
            }
            CloseWindow();
        }

        public void UpdateData()
        {
            if (!multiSelect)
            {
                noteType.value = (int)noteData.type;
                direction.value = (int)dir;
                time.text = noteData.beatTime.ToString();
                holdTime.text = noteData.beatHoldTime.ToString();
                speed.text = noteData.speed.ToString();
                posX.text = noteData.positionX.ToString();
            }
            else
            {
                try
                {
                    if (dats.type != null) noteType.value = (int)dats.type;
                    else noteType.value = 4;

                    if (dirs != null) direction.value = (int)dirs;
                    else direction.value = 2;
                    //print((int)dirs);
                }
                catch (Exception ex)
                {
                    Debug.LogError("Dropdown set value error, msg:" + ex.Message);
                }
                if (dats.beatTime != null) time.text = dats.beatTime.ToString();
                else time.text = "-";
                if (dats.beatHoldTime != null) holdTime.text = dats.beatHoldTime.ToString();
                else holdTime.text = "-";
                if (dats.speed != null) speed.text = dats.speed.ToString();
                else speed.text = "-";
                if (dats.positionX != null && dats.positionX != "-") posX.text = dats.positionX;
                else posX.text = "-";
            }
        }

        public void Clone()
        {
            if (!cloningNote && multiSelect)
                return;
            if (true)
            {
                cloningNote = true;
                StartCoroutine(CloneNote());
            }
        }

        IEnumerator CloneNote()
        {
            NoteGlobalView.Note.NoteData data = new NoteGlobalView.Note.NoteData
            {
                type = (NoteGlobalView.NoteType)selectNote.type,
                positionX = selectNote.noteData.positionX,
                speed = selectNote.noteData.speed,
                beatTime = selectNote.noteData.beatTime,
                beatHoldTime = selectNote.noteData.beatHoldTime
            };
            Note n = LevelController.instance.notesManager.InstantiateNote(
                            NoteGlobalView.LevelController.instance.notesManager.InstantiateNote(
                                (NoteGlobalView.NoteType)selectNote.type,
                                data,
                                NoteGlobalView.JudgementLine.selectedJudgeline,
                                (NoteGlobalView.Note.Direction)selectNote.direction),
                            LevelController.instance.judgelines[0]
                            );
            //NotesManager.instance.InstantiateNote(selectNote.type, selectNote.noteData, selectNote.judgeline, selectNote.direction);
            for (; ; )
            {
                if (CanGenerateNote() && Input.GetMouseButtonDown(0))
                    break;
                print(1);
                n.noteData.positionX = new Vector3(cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x - RectToMouse(re).x, Input.mousePosition.y - RectToMouse(re).y, LevelController.instance.camDistance)).x, cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x - RectToMouse(re).x, Input.mousePosition.y - RectToMouse(re).y, 8)).y, 0).x;
                yield return null;
            }
            cloningNote = false;
            yield return null;
        }

        public bool CanGenerateNote()
        {
            return Input.mousePosition.x - RectToMouse(re).x < re.sizeDelta.x && Input.mousePosition.x - RectToMouse(re).x > 0;
        }

        public Vector2 RectToMouse(RectTransform rect)
        {
            Vector2 res = Vector2.zero;
            res.x = rect.anchoredPosition.x + Screen.width / 2 - rect.sizeDelta.x / 2;
            res.y = rect.anchoredPosition.y + Screen.height / 2 - rect.sizeDelta.y / 2;
            return res;
        }

        public void Submit()
        {
            if (!multiSelect)
            {
                selectNote.noteData.type = noteData.type;
                selectNote.noteData.beatTime = noteData.beatTime;
                selectNote.noteData.beatHoldTime = noteData.beatHoldTime;
                selectNote.noteData.speed = noteData.speed;
                selectNote.noteData.positionX = noteData.positionX;
                selectNote.direction = dir;
            }
            else
            {
                float[] values = new float[selectNotes.Count];
                if (dats.positionX != null && dats.positionX != "-")
                {
                    if (dats.positionX.Contains("—"))
                    {
                        string input = dats.positionX;
                        float start = float.Parse(input.Split('—')[0]);
                        float end = float.Parse(input.Split('—')[1]);
                        if (input.Split('—').Length < 3)
                        {
                            input += "—linear";
                        }
                        string curve = input.Split('—')[2];
                        switch (curve)
                        {
                            case "linear":
                                {
                                    values[0] = start;
                                    float delta = (end - start) / selectNotes.Count;
                                    float val = start;
                                    for (int i = 1; i < selectNotes.Count; i++)
                                    {
                                        values[i] = val += delta;
                                    }
                                }
                                break;

                            case "sin":
                                {
                                    for (int i = 0; i < selectNotes.Count; i++)
                                    {
                                        values[i] = Mathf.Clamp((float)Math.Sin(i), start, end);
                                    }
                                }
                                break;
                        }
                    }
                    else
                    {
                        values = new float[1];
                        values[0] = float.Parse(dats.positionX);
                    }
                }
                else
                {
                    values = new float[1];
                    values[0] = float.NaN;
                }
                for (int i = 0; i < selectNotes.Count; i++)
                {
                    if (dats.type != null) selectNotes[i].noteData.type = (NoteType)dats.type;
                    if (dirs != null) selectNotes[i].direction = (Note.Direction)dirs;
                    if (dats.beatTime != null) selectNotes[i].noteData.beatTime = (int)dats.beatTime;
                    if (dats.beatHoldTime != null) selectNotes[i].noteData.beatHoldTime = (int)dats.beatHoldTime;
                    if (dats.speed != null) selectNotes[i].noteData.speed = (float)dats.speed;
                    if (values.Length == 1)
                    {
                        if (!float.IsNaN(values[0])) selectNotes[i].noteData.positionX = values[0];
                    }
                    else
                    {
                        selectNotes[i].noteData.positionX = values[i];
                        print(selectNotes[i].noteData.positionX == values[i]);
                    }
                }
            }
            CloseWindow();
        }

        public void CloseWindow()
        {
            NoteDataEditManager.instance.CloseWindow();
        }

        public void Delete()
        {
            if (!multiSelect)
            {
                Destroy(selectNote.gameObject);

            }
            else
            {
                for (int i = 0; i < selectNotes.Count; i++)
                {
                    Destroy(selectNotes[i].gameObject);
                }
            }
            NoteDataEditManager.instance.CloseWindow();
        }

        public void Cancel()
        {
            CloseWindow();
        }
    }
}
